<?php
// +----------------------------------------------------------------------
// | HisiPHP框架[基于ThinkPHP5.1开发]
// +----------------------------------------------------------------------
// | Copyright (c) 2016-2021 http://www.HisiPHP.com
// +----------------------------------------------------------------------
// | HisiPHP承诺基础框架永久免费开源，您可用于学习和商用，但必须保留软件版权信息。
// +----------------------------------------------------------------------
// | Author: 橘子俊 <364666827@qq.com>，开发者QQ群：50304283
// +----------------------------------------------------------------------

namespace app\common\service;

use app\common\service\Base;
use think\facade\Cache;


class Tree
{
    private static $tem_arr = []; // 树排序时需要的数据结构

    /**
     * 将数组转化成树型结构
     * @param $arr array 待转化的数组
     * @param $top_pid string|int 根级pid 要求顶级父id为0
     * @param $id_str string id字段名
     * @param $pid_str string pid字段名
     * @param $child_name string 将要存放的孩子名称
     * @param $isIdToKey bool 是否将id作为key(默认否)
     * @return array
     */
    static function array2tree_xm_select(&$arr, $select_ids = [], $top_pid = 0, $level = 0, $id_str = 'id', $pid_str = 'pid', $child_name = 'children', $isIdToKey = false)
    {
        if (empty($arr)) return $arr;
        $tem_arr = array();
        foreach ($arr as $key => $value) {
            //循环找到pid是当前pid的行
            if (($key !== $child_name) && ($value[$pid_str] == $top_pid)) {
                unset($arr[$key]);
                $child_result = self::array2tree_xm_select($arr, $select_ids, $value[$id_str], $level + 1, $id_str, $pid_str, $child_name, $isIdToKey);
                $value['tree_level'] = $level;
                $value['value'] = $value['id'];//xm_select设置用的
                in_array($value['id'], $select_ids) && $value['selected'] = true;
                if ($isIdToKey) {
                    $tem_arr[$child_name][$value[$id_str]] = array_merge($value, $child_result);
                } else {
                    $tem_arr[$child_name][] = array_merge($value, $child_result);
                }
            }
        }
        if ($level == 0) return $tem_arr[$child_name];
        return $tem_arr;
    }

    /**
     * 将数组转化成树型结构
     * @param $arr array 待转化的数组
     * @param $top_pid string|int 根级pid 要求顶级父id为0
     * @param $id_str string id字段名
     * @param $pid_str string pid字段名
     * @param $child_name string 将要存放的孩子名称
     * @param $isIdToKey bool 是否将id作为key(默认否)
     * @return array
     */
    static function array2tree(&$arr, $top_pid = 0, $level = 0, $id_str = 'id', $pid_str = 'pid', $child_name = 'child', $isIdToKey = true)
    {
        if (empty($arr)) return $arr;
        $tem_arr = array();
        foreach ($arr as $key => $value) {
            //循环找到pid是当前pid的行
            if (($key !== $child_name) && ($value[$pid_str] == $top_pid)) {
                unset($arr[$key]);
                $child_result = self::array2tree($arr, $value[$id_str], $level + 1, $id_str, $pid_str, $child_name, $isIdToKey);
                $value['tree_level'] = $level;
                if ($isIdToKey) {
                    $tem_arr[$child_name][$value[$id_str]] = array_merge($value, $child_result);
                } else {
                    $tem_arr[$child_name][] = array_merge($value, $child_result);
                }
            }
        }
        if ($level == 0) return $tem_arr[$child_name];
        return $tem_arr;
    }

    /**
     * 数组转顺序数组
     * @param $arr array 待转化的数组
     * @param $relation_field string 需要加关系缩进的字段
     * @param $id_str string id字段名
     * @param $pid_str string pid字段名
     * @param $child_name string 将要存放的孩子名称
     * @return array
     * @throws
     */
    static function array2orderArr($arr, $relation_field = '', $id_str = 'id', $pid_str = 'pid', $child_name = 'child', $topParentIdVal = '')
    {
        if (empty($arr)) return [];
        // 验证, 如果不满足条件, 则退出
        $first_data = current($arr);
        if (empty($arr)) return [];
        if (!is_array($arr) || !isset($first_data[$id_str]) || !isset($first_data[$pid_str])) {
            throw new \RuntimeException('数组错误，不存在或未设置正确参数');
        }
        // 进行树关系排序
        self::$tem_arr = array();
        self::_selfJoinArrayOrder($arr, $topParentIdVal, 0, $id_str, $pid_str, $child_name);

        // 修饰层级 需要设置relation_field参数
        if (!empty($relation_field) and !empty(self::$tem_arr) and isset(self::$tem_arr[0][$relation_field])) {
            foreach (self::$tem_arr as $key => &$val) {
                $val['_tree_display_pre_str'] = '';
                if ($val['_tree_level'] > 0) {
                    $tem_val = str_pad('', $val['_tree_level'] * 6, '　');
                    $tem_val .= (isset(self::$tem_arr[$key + 1]) and ($val['_tree_level']) <= self::$tem_arr[$key + 1]['_tree_level']) ? '├─' : '└─';
                    $val['_tree_display_pre_str'] = $tem_val;
                }
            }
        }

        return self::$tem_arr;
    }

    /**
     * 自连接数组顺序化
     * @param $arr array 待转化的数组
     * @param $top_pid_value int 根级pid 要求顶级父id为0
     * @param $level int 自动给
     * @param $id_str string id字段名
     * @param $pid_str string pid字段名
     * @param $child_name string 将要存放的孩子名称
     */
    static private function _selfJoinArrayOrder(&$arr, $top_pid_value = 0, $level = 0, $id_str = 'id', $pid_str = 'pid', $child_name = 'child')
    {
        foreach ($arr as $key => &$value) {
            $value['_tree_level'] = $level;
            //循环找到pid是当前pid的行
            if (($key !== $child_name) && ($value[$pid_str] == $top_pid_value)) {
                self::$tem_arr[] = $value;
                unset($arr[$key]);
                self::_selfJoinArrayOrder($arr, $value[$id_str], $level + 1, $id_str, $pid_str, $child_name);
            }
        }
    }
}

class Factory extends Base
{

    public $temp = [];
    public $temp2 = [];
    public $user_f_ids = [];

    /**
     * 获取键值对缓存
     *
     * @param bool $isAll 是否显示所有（true是，false只显示自己权限内的）
     *
     * @return array
     * @author KING
     * @date 2020年6月9日
     *
     */
    public function getKVCache($isAll = true)
    {
        if (env('order_level') == 1) {
//            $factory_user = session('factory_user');
//            if ($factory_user == null) {
//                $factory_user = [];
//                $list_tree = $this->getAllTree_0_role([]);
//                foreach ($list_tree as $k => $v) {
//                    $factory_user[$v['id']] = $v['name'];
//                }
//                session('factory_user', $factory_user);
//            }
//            return $factory_user;
        }
        $data = cache(KV_FACTORY);
        if (!$data) {
            $data = $this->updateKVCache();
        }
        if ($isAll || FACTORY_IDS == '*') return $data;
        $factoryArr = explode(',', FACTORY_IDS);
        $result = [];
        foreach ($data as $factoryId => $factoryName) {
            if (in_array($factoryId, $factoryArr)) {
                $result[$factoryId] = $factoryName;
            }
        }
        return $result;
    }

    /**
     * 更新键值对缓存
     *
     * @author KING
     * @date 2020年6月9日
     *
     */
    public function updateKVCache()
    {
        $list = $this->getKVList(1);
        cache(KV_FACTORY, $list);
        return $list;
    }

    /**
     * 获取键值对列表
     *
     * @param integer $status
     * @return array
     * @author KING
     * @date 2020年6月9日
     *
     */
    public function getKVList($status = 1)
    {
        $where = [
            'pid' => 0,
        ];
        if ($status !== null) $where['status'] = $status;
        $order = "order desc, id desc";
        return db('factory')->where($where)->order($order)->column('name', 'id');
    }

    /**
     * 获取所有工厂树
     * @param int $pid 父id
     * @param array $select_ids 标识在xm_select里已经选择的节点
     * @author zhuguosen 905502314@qq.com
     * @date 2022/4/24
     */
    public function getAllTree($select_ids = [])
    {
        $list = $temp = db('factory')->field("id,pid,name")->whereRaw("status=1")->order('order desc,id desc')->select();
        $list_tree = Tree::array2tree_xm_select($temp, $select_ids);
        return [$list, $list_tree];
    }

    /**
     * 获取所有工厂树--原树
     * @param array $select_ids 标识在xm_select里已经选择的节点
     * @author zhuguosen 905502314@qq.com
     * @date 2022/4/24
     */
    public function getAllTree_0($select_ids = [])
    {
        //1，树查询
        if (trim(FACTORY_IDS) == '' && SUB_FACTORY_ID <= 0) {
            return [];
        }
        $list_tree = $this->tree_span($select_ids);
        //2,树转一维数组
        $res_list = [];
        $res_list[] = ['id' => 0, 'name' => '请选择',];
        foreach ($list_tree as $k => $v) {
            $res_list[] = $v;
            if (isset($v['children'])) {
                foreach ($v['children'] as $k2 => $v2) {
                    $v2['name'] = "└─{$v2['name']}";
                    $res_list[] = $v2;
                    if (isset($v2['children'])) {
                        foreach ($v2['children'] as $k3 => $v3) {
                            $v3['name'] = "&nbsp;&nbsp;└─{$v3['name']}";
                            $res_list[] = $v3;
                            if (isset($v3['children'])) {
                                foreach ($v3['children'] as $k4 => $v4) {
                                    $v4['name'] = "&nbsp;&nbsp;&nbsp;&nbsp;└─{$v4['name']}";
                                    $res_list[] = $v4;
                                }
                            }
                        }
                    }
                }
            }
        }
        return $res_list;
    }

    /**
     * 获取所有工厂树--原树--结合用户权限，得了相应树
     * @param array $select_ids 标识在xm_select里已经选择的节点
     * @author zhuguosen 905502314@qq.com
     * @date 2022/4/24
     */
    public function getAllTree_0_role($select_ids = [])
    {
        //1，树查询
        if (trim(FACTORY_IDS) == '' && SUB_FACTORY_ID <= 0) {
            return [];
        }
        $list_tree = $this->tree_span($select_ids, 1);
        //2,树转一维数组
        $res_list = [];
        $res_list[] = ['id' => 0, 'name' => '请选择',];
        foreach ($list_tree as $k => $v) {
            $res_list[] = $v;
            if (isset($v['children'])) {
                foreach ($v['children'] as $k2 => $v2) {
                    $v2['name'] = "└─{$v2['name']}";
                    $res_list[] = $v2;
                    if (isset($v2['children'])) {
                        foreach ($v2['children'] as $k3 => $v3) {
                            $v3['name'] = "&nbsp;&nbsp;└─{$v3['name']}";
                            $res_list[] = $v3;
                            if (isset($v3['children'])) {
                                foreach ($v3['children'] as $k4 => $v4) {
                                    $v4['name'] = "&nbsp;&nbsp;&nbsp;&nbsp;└─{$v4['name']}";
                                    $res_list[] = $v4;
                                }
                            }
                        }
                    }
                }
            }
        }
        return $res_list;
    }


    /**
     * 树查询-用户权限内的树查询
     * @param $select_ids
     * @param int $flag 0相对完整 1不完整
     * @return array
     * @author zhuguosen 905502314@qq.com
     * @date 2022/4/26
     */
    public function tree_span($select_ids = [], $flag = 0)
    {
        if (trim(FACTORY_IDS) == '' && SUB_FACTORY_ID <= 0) {
            return [];
        }
        $list = db('factory')->field("id,pid,name")->whereRaw("status=1")->order('order desc,id desc')->select();
        $list_tree = $list_tree_source = Tree::array2tree_xm_select($list, $select_ids);
        if (trim(FACTORY_IDS) == '*') {
            return $list_tree;
        }
        $FACTORY_IDS_temp = [];
        if (trim(FACTORY_IDS) != '' && trim(FACTORY_IDS) != '*') {//主树修整
            $FACTORY_IDS_temp = explode(',', FACTORY_IDS);
        }
        if (SUB_FACTORY_ID > 0) {
            $this->temp = [];
            $this->getParentStr(SUB_FACTORY_ID);
            $this->temp = array_reverse($this->temp);
            $FACTORY_IDS_temp[] = $this->temp[0];
        }
        $list_tree_temp = [];
        foreach ($list_tree as $k => $v) {
            if (trim(FACTORY_IDS) == '*') {
                $list_tree_temp[] = $v;
                continue;
            }
            if (in_array($v['id'], $FACTORY_IDS_temp)) {
                $list_tree_temp[] = $v;
            }
        }
        switch ($flag) {
            case 0:
                return $list_tree_temp;
                break;
            case 1:
                if (SUB_FACTORY_ID <= 0) {
                    return $list_tree_temp;
                }
                $this->temp = [];
                $parentList = $this->getParentStr(SUB_FACTORY_ID);
                $this->temp = array_reverse($this->temp);
                $FACTORY_IDS_temp_real = [];
                if (trim(FACTORY_IDS) != '') {
                    $FACTORY_IDS_temp_real = explode(',', FACTORY_IDS);
                }
                $list_tree_res = [];
                foreach ($list_tree_temp as $k => $v) {
                    if ($FACTORY_IDS_temp_real != [] && in_array($v['id'], $FACTORY_IDS_temp_real)) {
                        $list_tree_res[] = $v;
                        continue;
                    }
                    $this->temp2 = [];
                    $min_pid = $this->temp[count($this->temp) - 1];
                    $this->get_min_tree($v['children'], $min_pid);
                    $list_tree_res[] = $this->temp2;
                }
                return $list_tree_res;
                break;
        }
        return $list_tree;
    }

    /**
     * 树转数据id
     * @param $tree
     * @author zhuguosen 905502314@qq.com
     * @date 2022/4/26
     */
    public function get_tree_span_str($tree)
    {
        foreach ($tree as $k => $v) {
            $this->temp[] = $v;
            if (isset($v['children'])) {
                $this->get_tree_span_str($v['children']);
            }
        }
        return true;
    }

    /**
     * 用户权限内的工厂id集
     * @return array
     * @author zhuguosen 905502314@qq.com
     * @date 2022/4/26
     */
    public function user_f_ids()
    {
        if ($this->user_f_ids == []) {//缓存在对象里就可以了
            $tree_span = $this->tree_span([], 1);
            $this->temp = [];
            $this->get_tree_span_str($tree_span);
            $f_ids = [];//权限内的工厂id集
            foreach ($this->temp as $k => $v) {
                $f_ids[] = $v['id'];
            }
            $this->user_f_ids = $f_ids;
            return $f_ids;
        }
        return $this->user_f_ids;
    }

    /**
     * 树的修剪   小树+ 连 [2,99,33]
     * @param $tree
     * @param $pids
     * @return array
     * @author zhuguosen 905502314@qq.com
     * @date 2022/5/9
     */
    public function get_min_tree($tree, $min_pid)
    {
        if ($this->temp2 != []) {
            return $this->temp2;
        }
        foreach ($tree as $k => $v) {
            if ($v['id'] == $min_pid) {
                $this->temp2 = $v;
                return $this->temp2;
            }
            if (isset($v['children'])) {
                $this->get_min_tree($v['children'], $min_pid);
            }
        }
        return [];
    }

    /**
     * 获取所有工厂树--原树
     * @param array $select_ids 标识在xm_select里已经选择的节点
     * @author zhuguosen 905502314@qq.com
     * @date 2022/4/24
     */
    public function getAllTree_0_old2($select_ids = [])
    {
        $list = $temp = db('factory')->field("id,pid,name")->whereRaw("status=1")->order('order desc,id desc')->select();
        $list_tree = Tree::array2tree_xm_select($temp, $select_ids);
        $res_list = [];
        $res_list[] = ['id' => 0, 'name' => '请选择',];
        foreach ($list_tree as $k => $v) {
            $res_list[] = $v;
            if (isset($v['children'])) {
                foreach ($v['children'] as $k2 => $v2) {
                    $v2['name'] = "└─{$v2['name']}";
                    $res_list[] = $v2;
                    if (isset($v2['children'])) {
                        foreach ($v2['children'] as $k3 => $v3) {
                            $v3['name'] = "&nbsp;&nbsp;└─{$v3['name']}";
                            $res_list[] = $v3;
                            if (isset($v3['children'])) {
                                foreach ($v3['children'] as $k4 => $v4) {
                                    $v4['name'] = "&nbsp;&nbsp;&nbsp;&nbsp;└─{$v4['name']}";
                                    $res_list[] = $v4;
                                }
                            }
                        }
                    }
                }
            }
        }
        return $res_list;
    }

    /**
     * 获取所有工厂树--原树
     * @param array $select_ids 标识在xm_select里已经选择的节点
     * @author zhuguosen 905502314@qq.com
     * @date 2022/4/24
     */
    public function getAllTree_0_old($select_ids = [])
    {
        $list = $temp = db('factory')->field("id,pid,name")->whereRaw("status=1")->order('order desc,id desc')->select();
        $list_tree = Tree::array2tree_xm_select($temp, $select_ids);
        $res_list = [0 => '请选择'];
        foreach ($list_tree as $k => $v) {
            $res_list[$v['id']] = $v['name'];
            if (isset($v['children'])) {
                foreach ($v['children'] as $k2 => $v2) {
                    $res_list[$v2['id']] = "->{$v2['name']}";
                    if (isset($v2['children'])) {
                        foreach ($v2['children'] as $k3 => $v3) {
                            $res_list[$v3['id']] = "->->{$v3['name']}";
                            if (isset($v3['children'])) {
                                foreach ($v3['children'] as $k4 => $v4) {
                                    $res_list[$v4['id']] = "->->->{$v4['name']}";
                                }
                            }
                        }
                    }
                }
            }
        }
        return $res_list;
    }


    /**
     * 获取此节点的所有子工厂树
     * @param $id
     * @author zhuguosen 905502314@qq.com
     * @date 2022/4/24
     */
    public function getChildTree($pid = 0, $child_name = 'child')
    {
        $list = db('factory')->field("id,pid,name")->whereRaw("status=1 and pid={$pid}")->order('order desc,id desc')->select();
        if ($list != []) {
            foreach ($list as $k => $v) {
                $this->temp[] = $v['id'];//收集所有树id
                $list[$k][$child_name] = $this->getChildTree($v['id']);
            }
        }
        return $list;
    }

    /**
     * 找此节点的父路径
     * @param int $id
     * @author zhuguosen 905502314@qq.com
     * @date 2022/4/25
     */
    public function getParentStr($id = 0)
    {
        $info = db('factory')->field("id,pid,name")->whereRaw("id={$id}")->order('order desc,id desc')->find();
        $this->temp[] = $info['id'];//收集所有树id
        if ($info['pid'] > 0) {
            $info['parent'] = $this->getParentStr($info['pid']);
        }
        return $info;
    }

    /**
     * 找此节点的父路径--信息相对全面
     * @param int $id
     * @author zhuguosen 905502314@qq.com
     * @date 2022/5/9
     */
    public function getParentStr_all_info($id = 0)
    {
        $info = db('factory')->field("id,pid,name")->whereRaw("id={$id}")->order('order desc,id desc')->find();
        $this->temp[] = $info;//收集所有树id
        if ($info['pid'] > 0) {
            $info['parent'] = $this->getParentStr_all_info($info['pid']);
        }
        return $info;
    }

    /**
     * 获取order表的sub_factory_ids 的设置值
     *  list($factoryId,$sub_factory_ids)= (new Factory())->get_sub_factory_ids($factoryId);
     * @param int $factoryId
     * @return string
     * @author zhuguosen 905502314@qq.com
     * @date 2022/4/25
     */
    public function get_sub_factory_ids($factoryId = 0)
    {
        if ($factoryId <= 0) {
            return [0, ''];
        }
        $this->temp = [];
        $parentList = $this->getParentStr($factoryId);
        $this->temp = array_reverse($this->temp);
        return [$this->temp[0], implode(',', $this->temp)];
    }

    /**
     * 此工厂--对应的用户有没权限设置查询
     * @param int $factoryId
     * @return bool
     * @author zhuguosen 905502314@qq.com
     * @date 2022/4/25
     */
    public function set_factory_id_right($factoryId = 0)
    {
        if (env('order_level') != 1) {//原逻辑
            return true;
        }
        if (FACTORY_IDS == '*') {
            return true;
        }
        if ($factoryId <= 0 && FACTORY_IDS != '*') {
            return false;
        }
        switch (trim(FACTORY_IDS)) {
            case '':
                if (SUB_FACTORY_ID <= 0) {
                    return false;
                }
                $f_ids = $this->user_f_ids();//权限内的工厂id集
                if (in_array($factoryId, $f_ids)) {
                    return true;
                }
                return false;
                break;
            default:
                $f_ids = $this->user_f_ids();//权限内的工厂id集
                if (in_array($factoryId, $f_ids)) {
                    return true;
                }
                return false;
                break;
        }
        return true;
    }

    /**
     * 获取最小工厂id 与 父连的id与name信息
     * @param int $factoryId
     * @param string $sub_factory_ids
     * @return int
     * @author zhuguosen 905502314@qq.com
     * @date 2022/4/25
     */
    public function get_factory_id_min($factoryId = 0, $sub_factory_ids = '')
    {
        if (trim($sub_factory_ids) == '') {
            return [
                $factoryId,
                [],
            ];
        }
        $sub_factory_ids_array = explode(',', $sub_factory_ids);
        $parent_array = [];
        if (count($sub_factory_ids_array) > 1) {
            foreach ($sub_factory_ids_array as $k => $v) {
                $info = db('factory')->field("id,pid,name")->whereRaw("id={$v}")->find();
                $parent_array[] = $info;
            }
            unset($parent_array[count($parent_array) - 1]);
        }
        return [
            $sub_factory_ids_array[count($sub_factory_ids_array) - 1],
            $parent_array
        ];
    }

    /**
     * 获取最小工厂id 与 父连的id与name信息--结合用户权限，显示工厂连
     * @param int $factoryId
     * @param string $sub_factory_ids
     * @return int
     * @author zhuguosen 905502314@qq.com
     * @date 2022/4/25
     */
    public function get_factory_id_min_role($factoryId = 0, $sub_factory_ids = '')
    {
        if (trim($sub_factory_ids) == '') {
            return [
                $factoryId,
                [],
            ];
        }
        $sub_factory_ids_array = explode(',', $sub_factory_ids);
        $parent_array = [];
        if (count($sub_factory_ids_array) > 1) {
            foreach ($sub_factory_ids_array as $k => $v) {
                $info = db('factory')->field("id,pid,name")->whereRaw("id={$v}")->find();
                $parent_array[] = $info;
            }
            unset($parent_array[count($parent_array) - 1]);
        }
        //结合用户权限，显示工厂连
        $parent_array = $this->_get_factory_id_min_role_real($parent_array, $sub_factory_ids_array);
        return [
            $sub_factory_ids_array[count($sub_factory_ids_array) - 1],
            $parent_array
        ];
    }

    private function _get_factory_id_min_role_real($parent_array, $sub_factory_ids_array)
    {
        $f_ids = $this->user_f_ids();
        $can_show = [];
        foreach ($sub_factory_ids_array as $k => $v) {
            $flag = 0;
            foreach ($f_ids as $k2 => $v2) {
                if ($v == $v2) {
                    $flag = 1;
                    break;
                }
            }
            if ($flag == 0) {
                if (($k - 1) >= 0) unset($can_show[$k - 1]);
            }
            $can_show[$k] = $v;
        }
        $parent_array_res = [];
        foreach ($parent_array as $k => $v) {
            foreach ($can_show as $k2 => $v2) {
                if ($v['id'] == $v2) {
                    $parent_array_res[] = $v;
                }
            }
        }
        return $parent_array_res;
    }
}